package com.sikaryofficial.workbench.manager;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONReader;
import com.alibaba.fastjson2.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.beust.jcommander.internal.Sets;
import com.google.common.collect.Lists;
import com.sikaryofficial.common.core.constant.CacheBusinessConstants;
import com.sikaryofficial.common.core.constant.CacheConstants;
import com.sikaryofficial.common.core.domain.R;
import com.sikaryofficial.common.core.exception.ServiceException;
import com.sikaryofficial.common.core.utils.FileUrlUtils;
import com.sikaryofficial.common.core.utils.StringUtils;
import com.sikaryofficial.common.core.web.page.PageDomain;
import com.sikaryofficial.common.redis.service.RedisService;
import com.sikaryofficial.common.security.utils.SecurityUtils;
import com.sikaryofficial.system.api.OuterNetWorkbenchService;
import com.sikaryofficial.system.api.RemoteHiSMKDigDataService;
import com.sikaryofficial.system.api.RemoteUserService;
import com.sikaryofficial.system.api.domain.SysUser;
import com.sikaryofficial.system.api.domain.order.OrderCustomizedOpReq;
import com.sikaryofficial.system.api.domain.order.OrderHeaderVO;
import com.sikaryofficial.system.api.domain.order.OrderItemVO;
import com.sikaryofficial.system.api.model.FileInfo;
import com.sikaryofficial.system.api.model.att.AttachmentResp;
import com.sikaryofficial.system.api.model.outer.OrderPayInfoResp;
import com.sikaryofficial.system.api.model.outer.UploadPaymentVoucherReq;
import com.sikaryofficial.workbench.config.WorkBenchGoodsConfig;
import com.sikaryofficial.workbench.constant.*;
import com.sikaryofficial.workbench.domain.dto.req.order.*;
import com.sikaryofficial.workbench.domain.dto.resp.SysDictDataDTO;
import com.sikaryofficial.workbench.domain.dto.resp.membership.MembershipPolicyDTO;
import com.sikaryofficial.workbench.domain.dto.resp.order.*;
import com.sikaryofficial.workbench.domain.entity.*;
import com.sikaryofficial.workbench.domain.mapping.*;
import com.sikaryofficial.workbench.service.*;
import com.sikaryofficial.workbench.utils.DataCompareHelper;
import com.sikaryofficial.workbench.utils.EntityCodeUtils;
import com.sikaryofficial.workbench.utils.QLExpressUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author : wuweihong
 * @desc : 订单管理服务
 * @date : 2024-09-24
 */

@Service
@Slf4j
public class OrderManager {

    @Autowired
    private IOrderHeaderService orderHeaderService;

    @Autowired
    private IOrderItemService orderItemService;

    @Autowired
    private IOrderCustomizedService orderCustomizedService;

    @Autowired
    private IGoodsService goodsService;

    @Autowired
    private IPriceTierService priceTierService;

    @Autowired
    private RedisService redisService;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private IMembershipPolicyService membershipPolicyService;

    @Autowired
    private IGoodsRelationService goodsRelationService;

    @Autowired
    private RemoteUserService remoteUserService;

    @Autowired
    private RemoteHiSMKDigDataService hiSMKDigDataService;

    @Resource
    private OuterNetWorkbenchService outerNetWorkbenchService;

    @Autowired
    private IAttachmentService attachmentService;

    @Autowired
    private WorkBenchGoodsConfig goodsConfig;

    public static final BigDecimal ONE_HUNDRED = BigDecimal.valueOf(100);

    private String buildCartLockKey(Long userId) {
        // 同步操作购物车
        return MessageFormat.format(CacheConstants.SHOPPING_CART_LOCK_KEY, userId.toString());
    }


    private String buildCartLockKey() {
        // 同步操作购物车
        return buildCartLockKey(SecurityUtils.getUserId());
    }

    /**
     * 商品参数校验
     * 1. 口味数量必须达到MOQ
     *
     * @param goodsOrderReq 商品订单
     */
    private void validateGoodsOrder(GoodsOrderReq goodsOrderReq, List<GoodsRelation> goodsRelations) {
        List<OrderItemReq> validOrderItems = goodsOrderReq.getOrderItems().stream().
                filter(item -> Objects.nonNull(item.getQuantity())).collect(Collectors.toList());
        goodsOrderReq.setOrderItems(validOrderItems);
        if (CollUtil.isEmpty(goodsOrderReq.getOrderItems())) {
            throw new ServiceException("No goods flavor has been added.");
        }
        Map<Long, GoodsRelation> goodsRelationMap = goodsRelations.stream().collect(Collectors.toMap(GoodsRelation::getGoodsRelationId, goodsRelation -> goodsRelation));
        for (OrderItemReq orderItem : validOrderItems) {
            GoodsRelation goodsRelation = goodsRelationMap.get(orderItem.getGoodsRelationId());
            if (Objects.isNull(goodsRelation)) {
                throw new ServiceException("goods flavor " + orderItem.getTasteName() + " does not exist.");
            } else {
                if (Objects.nonNull(goodsRelation.getMinQuantity()) && orderItem.getQuantity() < goodsRelation.getMinQuantity()) {
                    throw new ServiceException("goods flavor " + orderItem.getTasteName() + " quantity is less than MOQ(" + goodsRelation.getMinQuantity() + ").");
                }
            }
        }
    }

    /**
     * 内网代客下单
     *
     * @param goodsList
     */
    public void helpCustomerPlaceOrder(List<GoodsOrderReq> goodsList) {
        if (CollUtil.isNotEmpty(goodsList)) {
            Long userId = goodsList.get(0).getUserId();
            log.info("userId: {}, goodsList: {}", userId, JSON.toJSONString(goodsList));
            for (GoodsOrderReq goodsOrderReq : goodsList) {
                addGoodsToCart(goodsOrderReq, false, userId);
            }
            this.getQuote(userId);
        }
    }

    public void placeCustomOrder(List<GoodsOrderReq> goodsList) {
        if (CollUtil.isNotEmpty(goodsList)) {
            Long userId = goodsList.get(0).getUserId();
            log.info("userId: {}, goodsList: {}", userId, JSON.toJSONString(goodsList));
            ShoppingCartDTO cartDTO = getShoppingCart(userId);
            if (Objects.isNull(cartDTO.getGoodsOrderItems())) {
                cartDTO = new ShoppingCartDTO();
                cartDTO.setGoodsOrderItems(Lists.newArrayList());
            }
            for (GoodsOrderReq goodsOrderReq : goodsList) {
                GoodsOrderDTO goodsOrderDTO = ShoppingCartMapping.INSTANCE.coverGoodsOrderToResp(goodsOrderReq);
                cartDTO.getGoodsOrderItems().add(goodsOrderDTO);
                redisService.setCacheObject(buildShoppingCartKey(userId), cartDTO);
            }
        }
        getQuote();
    }

    /**
     * 添加商品到购物车，需要校验参数
     *
     * @param goodsOrderReq
     * @return
     */
    public ShoppingCartDTO addGoodsToCart(GoodsOrderReq goodsOrderReq) {
        checkGoodsCart();
        return this.addGoodsToCart(goodsOrderReq, true, null);
    }

    private void checkGoodsCart() {
        Long userId = SecurityUtils.getUserId();
        if (Objects.isNull(userId) || userId.compareTo(0L) == 0) {
            log.info("用户ID为空或0");
            return;
        }
        R<SysUser> sysUserR = remoteUserService.getSysUserInfoCacheById(userId);
        if (R.isError(sysUserR)) {
            log.warn("获取用户信息失败");
            throw new ServiceException("User info error.");
        }
        SysUser sysUser = sysUserR.getData();
        Date currentDate = new Date();
        log.debug("当前时间: {}", currentDate);
        log.debug("合同期限: {}", sysUser.getFrameworkContractDuration());
        boolean flag = Boolean.TRUE.equals(sysUser.isHasValid()) && Objects.nonNull(sysUser.getFrameworkContractDuration())
                && sysUser.getFrameworkContractDuration().compareTo(currentDate) > 0;
        if (Boolean.FALSE.equals(flag)) {
            log.info("用户已认证且合同期限未到，不能添加购物车, 当前时间: {}, 合同期限: {}", currentDate, sysUser.getFrameworkContractDuration());
            throw new ServiceException("User not authenticated or contract period has expired");
        }
    }

    /**
     * 添加商品到用户购物车
     *
     * @param goodsOrderReq 商品订单参数
     * @param isNeedValid   是否需要校验参数
     * @return 购物车模型
     */
    public ShoppingCartDTO addGoodsToCart(GoodsOrderReq goodsOrderReq, boolean isNeedValid, Long userId) {
        // 1. 购物车是否创建, 没有则创建购物车， 有则添加到购物车
        // 2. 商品是否已经存在，存在则合并，不存在则新增
        List<GoodsRelation> goodsRelations = goodsRelationService.lambdaQuery()
                .eq(GoodsRelation::getDeletedVersion, 0)
                .eq(GoodsRelation::getGoodsId, goodsOrderReq.getGoodsId())
                .list();
        if (isNeedValid) {
            this.validateGoodsOrder(goodsOrderReq, goodsRelations);
        }
        userId = Objects.isNull(userId) ? SecurityUtils.getUserId() : userId;
        if (Objects.isNull(userId) || userId == 0L) {
            return new ShoppingCartDTO();
        }
        String cacheKey = buildShoppingCartKey(userId);
        ShoppingCartDTO cartDTO = null;
        if (Boolean.TRUE.equals(redisService.hasKey(cacheKey))) {
            cartDTO = redisService.getCacheObject(cacheKey);
        }
        if (Objects.isNull(cartDTO)) {
            cartDTO = new ShoppingCartDTO();
            cartDTO.setGoodsOrderItems(Lists.newArrayList());
        }
        GoodsOrderDTO goodsOrderDTO = ShoppingCartMapping.INSTANCE.coverGoodsOrderToResp(goodsOrderReq);
        // 查询商品信息
        Goods goods = goodsService.getOne(new LambdaQueryWrapper<Goods>()
                .eq(Goods::getGoodsId, goodsOrderReq.getGoodsId())
                .eq(Goods::getDeletedVersion, 0));
        if (Objects.isNull(goods)) {
            throw new ServiceException("Goods does not exist.");
        }
        // 同步操作购物车
        copyGoodsInfoToGoodsOrder(goodsOrderDTO, goods);
        addOrMergeGoods(cartDTO, goodsOrderDTO, goods);
        // 购物车写入缓存
        cartDTO.setCurrency(goods.getCurrency());
        cartDTO.setMembershipDiscount(getMembershipDiscount(cartDTO.getDiscountAmount()));
        RLock lock = redissonClient.getLock(buildCartLockKey());
        try {
            if (lock.tryLock(2000, 2000, TimeUnit.MICROSECONDS)) {
                redisService.setCacheObject(cacheKey, cartDTO);
            }
        } catch (Exception e) {
            log.error("There is a error that Goods add to cart, the cart is locked, please try later.");
            log.error("exception: {}", e);
            Thread.currentThread().interrupt();
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        calcDiscountedMemberPrice(cartDTO);
        return cartDTO;
    }

    /**
     * 添加或合并商品
     * 先判断合并，再计算
     *
     * @param cart          购物车
     * @param newGoodsOrder 新商品订单
     * @param goods         商品
     */
    private void addOrMergeGoods(ShoppingCartDTO cart, GoodsOrderDTO newGoodsOrder, Goods goods) {
        // 1. 合并同一商品同一口味
        // 2. 计算合并后的金额
        boolean isNewItem = true;
        List<GoodsOrderDTO> goodsOrders = cart.getGoodsOrderItems();
        GoodsOrderDTO existingOrder = null;
        for (GoodsOrderDTO goodsOrder : goodsOrders) {
            if (goodsOrder.getGoodsId().equals(newGoodsOrder.getGoodsId())) {
                isNewItem = false;
                Map<Long, OrderItemDTO> orderItemMap = goodsOrder.getOrderItems().stream()
                        .collect(Collectors.toMap(OrderItemDTO::getGoodsRelationId, orderItemDTO -> orderItemDTO));
                for (OrderItemDTO orderItemDTO : newGoodsOrder.getOrderItems()) {
                    if (orderItemMap.containsKey(orderItemDTO.getGoodsRelationId())) {
                        OrderItemDTO existingItem = orderItemMap.get(orderItemDTO.getGoodsRelationId());
                        existingItem.setQuantity(existingItem.getQuantity() + orderItemDTO.getQuantity());
                        orderItemMap.put(existingItem.getGoodsRelationId(), existingItem);
                    } else {
                        orderItemMap.put(orderItemDTO.getGoodsRelationId(), orderItemDTO);
                    }
                }
                goodsOrder.setOrderItems(new ArrayList<>(orderItemMap.values()));
                existingOrder = goodsOrder;
                break;
            }
        }
        if (isNewItem) {
            existingOrder = newGoodsOrder;
            goodsOrders.add(existingOrder);
        }
        updateShoppingCart(existingOrder, goods, cart);
    }

    /**
     * 计算商品价格，填充商品属性，更新购物车的总价、折扣
     *
     * @param changingGoods
     * @param goods
     * @param cart
     */
    private void updateShoppingCart(GoodsOrderDTO changingGoods, Goods goods, ShoppingCartDTO cart) {
        try {
            BigDecimal oldGoodsDiscountAmount = Objects.nonNull(changingGoods.getDiscountAmount()) ? changingGoods.getDiscountAmount() : new BigDecimal(0);
            BigDecimal oldGoodsDiscount = Objects.nonNull(changingGoods.getDiscount()) ? changingGoods.getDiscount() : new BigDecimal(0);
            calcAndFillGoodsProperties(changingGoods, goods);
            if (Objects.isNull(cart.getDiscountAmount())) {
                cart.setDiscountAmount(changingGoods.getDiscountAmount());
            } else {
                cart.setDiscountAmount(QLExpressUtils.calculateUpdatePrice(cart.getDiscountAmount(), oldGoodsDiscountAmount, changingGoods.getDiscountAmount()));
            }
            if (Objects.isNull(cart.getDiscount())) {
                cart.setDiscount(changingGoods.getDiscount());
            } else {
                cart.setDiscount(QLExpressUtils.calculateUpdatePrice(cart.getDiscount(), oldGoodsDiscount, changingGoods.getDiscount()));
            }
        } catch (Exception e) {
            throw new ServiceException("Goods add to shopping cart error. " + e.getMessage());
        }
    }

    /**
     * 删除购物车的商品
     *
     * @param goodsId 商品编码
     * @return 购物车模型
     */
    public ShoppingCartDTO removeGoods(Long goodsId) {
        // 获取购物车
        ShoppingCartDTO cartDTO = loadShoppingCartCache();
        List<GoodsOrderDTO> goodsOrders = cartDTO.getGoodsOrderItems();
        GoodsOrderDTO goodsOrderDTO = goodsOrders.stream().filter(item -> item.getGoodsId().equals(goodsId)).findFirst().orElse(null);
        if (Objects.isNull(goodsOrderDTO)) {
            return cartDTO;
        }
        // 更新购物车
        // 同步操作购物车
        RLock lock = redissonClient.getLock(buildCartLockKey());
        try {
            if (lock.tryLock(2000, 2000, TimeUnit.MICROSECONDS)) {
                cartDTO.setDiscountAmount(cartDTO.getDiscountAmount().subtract(goodsOrderDTO.getDiscountAmount()));
                cartDTO.setDiscount(cartDTO.getDiscount().subtract(goodsOrderDTO.getDiscount()));
                goodsOrders.removeIf(item -> item.getGoodsId().equals(goodsId));
                cartDTO.setMembershipDiscount(getMembershipDiscount(cartDTO.getDiscountAmount()));
                // 更新缓存
                String cacheKey = buildShoppingCartKey();
                redisService.setCacheObject(cacheKey, cartDTO);
            }
        } catch (Exception e) {
            log.error("There is a error that Goods remove to cart, the cart is locked, please try later.");
            log.error("exception: {}", e);
            Thread.currentThread().interrupt();
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        calcDiscountedMemberPrice(cartDTO);
        return cartDTO;
    }

    public GoodsOrderDTO calcGoodsAmount(GoodsOrderReq goodsOrderReq) {
        GoodsOrderDTO goodsOrderDTO = ShoppingCartMapping.INSTANCE.coverGoodsOrderToResp(goodsOrderReq);
        Goods goods = goodsService.lambdaQuery()
                .eq(Goods::getDeletedVersion, 0)
                .eq(Goods::getGoodsId, goodsOrderReq.getGoodsId())
                .one();
        if (Objects.isNull(goods)) {
            throw new ServiceException("Goods does not exist.");
        }
        BigDecimal currUnitPrice = Objects.nonNull(goods.getCurrentWholesaleUnitPrice()) ? goods.getCurrentWholesaleUnitPrice() : goods.getWholesaleUnitPrice();
        goodsOrderDTO.setWholesaleUnitPrice(currUnitPrice);
        calcAndFillGoodsProperties(goodsOrderDTO, goods);
        return goodsOrderDTO;
    }

    /**
     * 计算商品折扣、总价、数量；填充子订单的属性
     *
     * @param goodsOrderDTO
     * @param goods
     */
    private void calcAndFillGoodsProperties(GoodsOrderDTO goodsOrderDTO, Goods goods) {
        // 1. 商品未折扣的总价 数量 折扣价 折扣金额
        long goodsQuantity = 0;
        List<BigDecimal> itemTotalPrices = new ArrayList<>(goodsOrderDTO.getOrderItems().size());
        for (OrderItemDTO item : goodsOrderDTO.getOrderItems()) {
            // 定制单不作计算
            if (Objects.isNull(item.getOrderCustomizedId())) {
                item.setUnitPrice(getGoodsPriceByQuantity(goodsOrderDTO.getGoodsId(), item.getQuantity()));
                goodsQuantity += item.getQuantity();
                item.setTotalPrice(QLExpressUtils.calculateTotalPrice(item.getUnitPrice(), item.getQuantity()));
	            assert goods != null;
	            item.setCurrency(goods.getCurrency());
                itemTotalPrices.add(item.getTotalPrice());
            }
            if (Objects.nonNull(goods)) {
                copyGoodsInfoToOrderItem(item, goods, null);
            }
        }
        BigDecimal goodsAmountNoDiscount = goodsOrderDTO.getWholesaleUnitPrice().multiply(new BigDecimal(goodsQuantity));
        BigDecimal goodsAmountDiscount = itemTotalPrices.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal goodsDiscount = goodsAmountNoDiscount.subtract(goodsAmountDiscount);
        goodsOrderDTO.setAmount(goodsAmountNoDiscount);
        goodsOrderDTO.setDiscount(goodsDiscount);
        goodsOrderDTO.setDiscountAmount(goodsAmountDiscount);
        goodsOrderDTO.setQuantity(goodsQuantity);
    }

    private ShoppingCartDTO loadShoppingCartCache(Long userId) {
        if (userId == 0L) {
            return new ShoppingCartDTO();
        }
        String cacheKey = buildShoppingCartKey(userId);
        ShoppingCartDTO cartDTO = new ShoppingCartDTO();
        if (Boolean.TRUE.equals(redisService.hasKey(cacheKey))) {
            cartDTO = redisService.getCacheObject(cacheKey);
        }
        return cartDTO;
    }

    private ShoppingCartDTO loadShoppingCartCache() {
        return loadShoppingCartCache(SecurityUtils.getUserId());
    }

    /**
     * 查看用户购物车
     *
     * @param userId 用户id
     * @return 购物车模型
     */
    public ShoppingCartDTO getShoppingCart(Long userId) {
        ShoppingCartDTO cartDTO = loadShoppingCartCache(userId);
        // 同步操作购物车
        updateGoodsInShoppingCart(cartDTO);
        calcDiscountedMemberPrice(cartDTO);
        return cartDTO;
    }

    /**
     * 查看用户购物车
     *
     * @return 购物车模型
     */
    public ShoppingCartDTO getShoppingCart() {
        return getShoppingCart(SecurityUtils.getUserId());
    }

    /**
     * 查询购物车信息时，更新购物车中的商品信息
     *
     * @param cartDTO 购物车
     */
    private void updateGoodsInShoppingCart(ShoppingCartDTO cartDTO) {
        if (Objects.isNull(cartDTO) || CollUtil.isEmpty(cartDTO.getGoodsOrderItems())) {
            return;
        }
        List<GoodsOrderDTO> goodsOrders = cartDTO.getGoodsOrderItems();
        List<Long> goodsIds = goodsOrders.stream().map(GoodsOrderDTO::getGoodsId).collect(Collectors.toList());
        List<Goods> goodsList = goodsService.lambdaQuery().in(Goods::getGoodsId, goodsIds).list();
        List<GoodsRelation> goodsRelationList = goodsRelationService.lambdaQuery().in(GoodsRelation::getGoodsId, goodsIds).list();
        Map<Long, Goods> goodsMap = goodsList.stream().collect(Collectors.toMap(Goods::getGoodsId, goods -> goods));
        Map<Long, GoodsRelation> goodsRelationMap = goodsRelationList.stream().collect(Collectors.toMap(GoodsRelation::getGoodsRelationId, goodsRelation -> goodsRelation));
        for (GoodsOrderDTO goodsOrder : goodsOrders) {
            Goods goods = goodsMap.get(goodsOrder.getGoodsId());
            if (Objects.isNull(goods)) {
                continue;
            }
            copyGoodsInfoToGoodsOrder(goodsOrder, goods);
            if (CollUtil.isNotEmpty(goodsOrder.getOrderItems())) {
                for (OrderItemDTO orderItem : goodsOrder.getOrderItems()) {
                    GoodsRelation goodsRelation = goodsRelationMap.get(orderItem.getGoodsRelationId());
                    if (Objects.isNull(goodsRelation)) {
                        continue;
                    }
                    copyGoodsInfoToOrderItem(orderItem, goods, goodsRelation);
                }
            }
        }
        // 同步操作购物车
        redisService.setCacheObject(buildShoppingCartKey(), cartDTO);
    }

    /**
     * 将商品信息复制到购物车的商品订单
     *
     * @param goodsOrder 复制的目标
     * @param goods      复制的来源
     */
    private void copyGoodsInfoToGoodsOrder(GoodsOrderDTO goodsOrder, Goods goods) {
        goodsOrder.setGoodsName(goods.getGoodsName());
        goodsOrder.setCoverUrl(goods.getCoverUrl());
        BigDecimal unitPrice = Objects.nonNull(goods.getCurrentWholesaleUnitPrice()) ? goods.getCurrentWholesaleUnitPrice() : goods.getWholesaleUnitPrice();
        goodsOrder.setWholesaleUnitPrice(unitPrice);
        goodsOrder.setCurrency(goods.getCurrency());
        goodsOrder.setBrandNo(goods.getBrandNo());
        Integer listingStatus = goods.getListingStatus();
        if (goods.getDeletedVersion() != 0) {
            listingStatus = 0;
        }
        goodsOrder.setListingStatus(listingStatus);
    }

    /**
     * 将商品信息和口味复制到购物车的商品子订单
     *
     * @param orderItem     拷贝的目标
     * @param goods         拷贝的来源
     * @param goodsRelation 该参数允许为null
     */
    private void copyGoodsInfoToOrderItem(OrderItemDTO orderItem, Goods goods, GoodsRelation goodsRelation) {
        if (Objects.nonNull(goodsRelation)) {
            orderItem.setProductNo(goodsRelation.getProductNo());
            orderItem.setTasteName(goodsRelation.getTasteName());
        }
        orderItem.setGoodsName(goods.getGoodsName());
        orderItem.setGoodsId(goods.getGoodsId());
        orderItem.setModel(goods.getModel());
        orderItem.setStyle(goods.getStyle());
    }

    /**
     * @param req 子订单请求模型
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateOrderItemInCart(OrderItemReq req) {
        ShoppingCartDTO cartDTO = loadShoppingCartCache();
        if (CollectionUtils.isEmpty(cartDTO.getGoodsOrderItems())) {
            throw new ServiceException("The shopping cart is empty and the operation cannot be completed.");
        }
        List<GoodsOrderDTO> goodsOrders = cartDTO.getGoodsOrderItems();
        GoodsOrderDTO currentGoods = null;
        for (GoodsOrderDTO goodsOrder : goodsOrders) {
            if (goodsOrder.getGoodsId().equals(req.getGoodsId())) {
                currentGoods = goodsOrder;
                break;
            }
        }
        if (Objects.isNull(currentGoods)) {
            throw new ServiceException("The goods not in the shopping cart and the operation cannot be completed.");
        }
        // 找到子订单，此时订单还未生成，因为同一商品口味唯一， 因此只能根据口味进行区分
        List<OrderItemDTO> orderItems = currentGoods.getOrderItems();
        for (OrderItemDTO orderItem : orderItems) {
            if (req.getGoodsRelationId().equals(orderItem.getGoodsRelationId())) {
                orderItem.setQuantity(req.getQuantity());
                orderItem.setUnitPrice(getGoodsPriceByQuantity(currentGoods.getGoodsId(), orderItem.getQuantity()));
                orderItem.setTotalPrice(QLExpressUtils.calculateTotalPrice(orderItem.getUnitPrice(), orderItem.getQuantity()));
            }
        }
        BigDecimal oldGoodsAmountDiscount = currentGoods.getDiscountAmount();
        BigDecimal oldGoodsDiscount = currentGoods.getDiscount();
        calcAndFillGoodsProperties(currentGoods, null);
        // 更新购物车信息
        cartDTO.setDiscountAmount(QLExpressUtils.calculateUpdatePrice(cartDTO.getDiscountAmount(), oldGoodsAmountDiscount, currentGoods.getDiscountAmount()));
        cartDTO.setDiscount(QLExpressUtils.calculateUpdatePrice(cartDTO.getDiscount(), oldGoodsDiscount, currentGoods.getDiscount()));
        // 更新缓存
        String cacheKey = buildShoppingCartKey();
        cartDTO.setMembershipDiscount(getMembershipDiscount(cartDTO.getDiscountAmount()));
        RLock lock = redissonClient.getLock(buildCartLockKey());
        try {
            if (lock.tryLock(2000, 2000, TimeUnit.MICROSECONDS)) {
                redisService.setCacheObject(cacheKey, cartDTO);
            }
        } catch (Exception e) {
            log.error("There is a error that change goods quantity in cart, the cart is locked, please try later.");
            log.error("exception: {}", e);
            Thread.currentThread().interrupt();
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    /**
     * 询价前订单还未生成
     * 生成主订单与子订单(根据品牌和标品定制生成）
     * 询价接口，变更订单状态，主订单：草稿-等待确认，子订单定制单：购物车-等待确定，非定制单：购物车-下单
     *
     * @param userId 用户id
     */
    @Transactional(rollbackFor = Exception.class)
    public SysUser getQuote(Long userId) {
        // 1. 根据品牌生成主订单
        // 获取购物车
        try {
            ShoppingCartDTO cartDTO = getShoppingCart(userId);
            checkBeforeQuote(loadShoppingCartCache(userId));
            if (CollectionUtils.isEmpty(cartDTO.getGoodsOrderItems())) {
                throw new ServiceException("Shopping cart is Empty.");
            }
            List<GoodsOrderDTO> goodsOrders = cartDTO.getGoodsOrderItems();
            Map<String, List<GoodsOrderDTO>> goodsOrdersByBrandNo = goodsOrders.stream().collect(Collectors.groupingBy(GoodsOrderDTO::getBrandNo));
            List<OrderHeader> orderHeaders = new ArrayList<>(goodsOrdersByBrandNo.size());
            List<OrderItem> orderItems = new ArrayList<>();
            for (Map.Entry<String, List<GoodsOrderDTO>> entry : goodsOrdersByBrandNo.entrySet()) {
                String brandNo = entry.getKey();
                List<GoodsOrderDTO> brandGoodsOrders = entry.getValue();
                // 生成子订单
                List<OrderItemDTO> orderItemDTOS = brandGoodsOrders.stream().map(GoodsOrderDTO::getOrderItems).flatMap(List::stream).collect(Collectors.toList());
                List<OrderItemDTO> stdOrderItemDTOs = orderItemDTOS.stream().filter(item -> Objects.isNull(item.getOrderCustomizedId())).collect(Collectors.toList());
                List<OrderItemDTO> cstmOrderItemDTOs = orderItemDTOS.stream().filter(item -> !Objects.isNull(item.getOrderCustomizedId())).collect(Collectors.toList());
                createOrders(brandNo, cartDTO.getMembershipDiscount(), stdOrderItemDTOs, orderHeaders, orderItems, userId);
                createOrders(brandNo, cartDTO.getMembershipDiscount(), cstmOrderItemDTOs, orderHeaders, orderItems, userId);
            }
            orderHeaderService.saveOrUpdateBatch(orderHeaders);
            orderItemService.saveOrUpdateBatch(orderItems);
            syncOrderToIntranet(orderHeaders, orderItems);
            String cacheKey = buildShoppingCartKey(userId);
            redisService.deleteObject(cacheKey);
	        return outerNetWorkbenchService.getSalesPhone(userId).getData();
        } catch (Exception e) {
            log.error("Error occurred while getting quote: {}", e.getMessage());
            throw new ServiceException("Error occurred while getting quote: " + e.getMessage());
        }
    }

    public SysUser getQuote() {
        return getQuote(SecurityUtils.getUserId());
    }

    /**
     * 同步订单到内网
     */
    private void syncOrderToIntranet(List<OrderHeader> orderHeaders, List<OrderItem> orderItems) {
        if (CollUtil.isNotEmpty(orderHeaders)) {
            List<OrderHeaderVO> orderHeaderVOS = new ArrayList<>(orderHeaders.size());
            for (OrderHeader orderHeader : orderHeaders) {
                OrderHeaderVO orderHeaderVO = OrderHeaderMapping.INSTANCE.coverHeaderToVO(orderHeader);
                if (Objects.nonNull(orderItems)) {
                    List<OrderItem> currOrderItems = orderItems.stream().filter(item -> item.getOrderHeaderId().equals(orderHeader.getOrderHeaderId())).collect(Collectors.toList());
                    List<OrderItemVO> currOrderItemVOs = OrderItemMapping.INSTANCE.coverItemListToVO(currOrderItems);
                    orderHeaderVO.setOrderItems(currOrderItemVOs);
                }
                orderHeaderVOS.add(orderHeaderVO);
            }
            log.info("同步订单到内网: {}", JSON.toJSONString(orderHeaderVOS));
            hiSMKDigDataService.syncOrder(orderHeaderVOS);
        }
    }

    private void syncConfirmOrRejectToIntranet(Long orderHeaderId, boolean isConfirmed, String remark) {
        OrderCustomizedOpReq opReq = new OrderCustomizedOpReq();
        opReq.setOrderHeaderId(orderHeaderId);
        opReq.setConfirmed(isConfirmed);
        opReq.setRemark(remark);
        outerNetWorkbenchService.confirmOrderCustomized(opReq);
    }

    /**
     * 询价下单前检查购物车是否有商品已下架，有则提示用户先移除该商品
     *
     * @param cart 购物车
     */
    private void checkBeforeQuote(ShoppingCartDTO cart) {
        if (Objects.nonNull(cart) && CollUtil.isNotEmpty(cart.getGoodsOrderItems())) {
            for (GoodsOrderDTO goodsOrder : cart.getGoodsOrderItems()) {
                if (GoodsListingStatusEnum.NO.getCode().equals(goodsOrder.getListingStatus())) {
                    throw new ServiceException("The goods " + goodsOrder.getGoodsName() + " has been taken off the shelf,Please remove this item from your shopping cart first.");
                }
            }
        }
    }


    /**
     * 根据提供的品牌编号和订单详情项列表来创建订单
     * 此方法首先检查源订单详情项列表是否为空,如果为空，则记录警告并返回
     * 否则，它将创建一个或多个子订单和一个主订单，具体取决于源订单详情项的数量
     * 每个子订单都与同一个主订单相关联，并且所有子订单的详细信息都会被计算并累加到主订单中
     *
     * @param brandNo             品牌编号，用于标识特定的品牌
     * @param sourceOrderItemDTOs 源订单详情项列表，包含多个订单项的信息
     * @param orderHeaders        订单头列表，用于存储创建的主订单信息
     * @param orderItems          订单项列表，用于存储创建的子订单信息
     */
    private void createOrders(String brandNo, BigDecimal membershipDiscount, List<OrderItemDTO> sourceOrderItemDTOs, List<OrderHeader> orderHeaders, List<OrderItem> orderItems, Long userId) {
        if (CollUtil.isEmpty(sourceOrderItemDTOs)) {
            // 子订单为空，不创建订单
            log.warn("Don't have any order items and can't create orders.");
            return;
        }
        // 创建子订单， 创建主单，sourceOrderItemDTOs属于同一个主单
        OrderHeader orderHeader = new OrderHeader();
        orderHeader.setOrderHeaderId(IdWorker.getId());
        orderHeader.setOrderHeaderNo(EntityCodeUtils.generateOrderHeaderNo());
        orderHeader.setBrandNo(brandNo);
        orderHeader.setHeaderStatus(OrderHeaderStatusEnum.WAITING_CONFIRMATION.getCode());
        orderHeader.setCreatedBy(userId);
        orderHeader.setCreatedTime(new Date());
        orderHeaders.add(orderHeader);
        long totalQuantity = 0;
        BigDecimal amount = new BigDecimal("0");
        boolean isCustomOrder = false;
        String currency = "";
        for (OrderItemDTO sourceItem : sourceOrderItemDTOs) {
            OrderItem orderItem = OrderItemMapping.INSTANCE.coverToEntity(sourceItem);
            orderItem.setOrderItemId(IdWorker.getId());
            orderItem.setOrderItemNo(EntityCodeUtils.generateOrderItemNo(brandNo));
            orderItem.setOrderHeaderId(orderHeader.getOrderHeaderId());
            orderItem.setItemStatus(OrderItemStatusEnum.ORDER_PLACEMENT.getCode());
            orderItem.setBrandNo(brandNo);
            orderItem.setCreatedBy(userId);
            currency = sourceItem.getCurrency();
            orderItem.setCurrency(sourceItem.getCurrency());
            orderItem.setCreatedBy(SecurityUtils.getUserId());
            orderItem.setCreatedTime(new Date());
            if (Objects.nonNull(orderItem.getOrderCustomizedId())) {
                isCustomOrder = true;
            } else {
                totalQuantity += orderItem.getQuantity();
                amount = amount.add(orderItem.getTotalPrice());
                orderItem.setTotalPrice(orderItem.getTotalPrice().multiply(membershipDiscount));
            }
            orderItems.add(orderItem);
        }
        if (isCustomOrder) {
            orderHeader.setHeaderStatus(OrderHeaderStatusEnum.DRAFT.getCode());
        }
        orderHeader.setCurrency(currency);
        orderHeader.setTotalQuantity(totalQuantity);
        if (Objects.nonNull(membershipDiscount)) {
            orderHeader.setAmount(amount.multiply(membershipDiscount));
        }
        orderHeaders.add(orderHeader);
    }


    /**
     * 分页查询订单（查询用户非草稿状态下的订单）
     *
     * @param req 分页查询请求参数
     * @return 分页查询列表
     */
    public IPage<OrderDTO> orderListPage(OrderListReq req) {
        Page<OrderDTO> customerPage = new Page<>(req.getPageNum(), req.getPageSize());
        Long userId = SecurityUtils.getUserId();
        if (userId == 0) {
            return new Page<>(req.getPageNum(), req.getPageSize(), 0);
        }
        IPage<OrderDTO> orderDTOIPage = orderHeaderService.orderList(customerPage, req, userId);
        if (orderDTOIPage.getRecords().isEmpty()) {
            return orderDTOIPage;
        }
        List<Long> orderHeaderIds = orderDTOIPage.getRecords().stream().map(OrderDTO::getOrderHeaderId).collect(Collectors.toList());
        List<OrderItem> allOrderItems = orderItemService.list(new LambdaQueryWrapper<OrderItem>()
                .in(OrderItem::getOrderHeaderId, orderHeaderIds)
                .eq(OrderItem::getDeletedVersion, 0)
        );
        Map<Long, List<OrderItem>> orderItemsByOrderHeaderId = allOrderItems.stream().collect(Collectors.groupingBy(OrderItem::getOrderHeaderId));
        orderDTOIPage.getRecords().forEach(orderDTO -> {
            // 填充子订单以及其他属性值
            orderDTO.setHeaderStatusDesc(OrderHeaderStatusEnum.getOrderHeaderStatusByCode(orderDTO.getHeaderStatus()).getDesc());
            Integer percentage = orderDTO.getHeaderStatus() * 100 / OrderHeaderStatusEnum.ORDER_COMPLETED.getCode();
            orderDTO.setPercentage(percentage);
            List<OrderItem> orderItems = MapUtils.getObject(orderItemsByOrderHeaderId, orderDTO.getOrderHeaderId(), Lists.newArrayList());
            List<OrderItemDTO> itemDTOS = OrderItemMapping.INSTANCE.coverListToResp(orderItems);
            // 为主订单及子订单填充额外属性
            fillOtherProperties(orderDTO, itemDTOS);
        });
        return orderDTOIPage;
    }

    /**
     * 运营侧-分页查询订单列表
     *
     * @param page
     */
    public IPage<OrderDTO> operateOrderList(PageDomain page) {
        Page<OrderHeader> operationPage = new Page<>(page.getPageNum(), page.getPageSize());
        IPage<OrderHeader> orderHeaderIPage = orderHeaderService.page(operationPage);
        IPage<OrderDTO> orderDTOIPage = orderHeaderIPage.convert(OrderHeaderMapping.INSTANCE::coverToResp);
        List<Long> orderHeaderIds = orderDTOIPage.getRecords().stream().map(OrderDTO::getOrderHeaderId).collect(Collectors.toList());
        if (CollUtil.isEmpty(orderHeaderIds)) {
            return orderDTOIPage;
        }
        List<OrderItem> allOrderItems = orderItemService.list(new LambdaQueryWrapper<OrderItem>()
                .in(OrderItem::getOrderHeaderId, orderHeaderIds)
                .eq(OrderItem::getDeletedVersion, 0)
        );
        Map<Long, List<OrderItem>> orderItemsByOrderHeaderId = allOrderItems.stream().collect(Collectors.groupingBy(OrderItem::getOrderHeaderId));
        orderDTOIPage.getRecords().forEach(orderDTO -> {
            // 填充子订单以及其他属性值
            R<SysUser> rUser = remoteUserService.getUserByUserId(orderDTO.getCreatedBy());
            String userName = "";
            if (Objects.nonNull(rUser.getData())) {
                SysUser user = rUser.getData();
                userName = Objects.isNull(user.getFirstName()) ? userName : userName + user.getFirstName();
                userName = Objects.isNull(user.getLastName()) ? userName : userName + user.getLastName();
            }
            orderDTO.setCreateUser(userName);
            orderDTO.setHeaderStatusDesc(OrderHeaderStatusEnum.getOrderHeaderStatusByCode(orderDTO.getHeaderStatus()).getDescCn());
            List<OrderItem> orderItems = MapUtils.getObject(orderItemsByOrderHeaderId, orderDTO.getOrderHeaderId(), Lists.newArrayList());
            List<OrderItemDTO> itemDTOS = OrderItemMapping.INSTANCE.coverListToResp(orderItems);
            // 为主订单及子订单填充额外属性
            fillOtherProperties(orderDTO, itemDTOS);
        });
        return orderDTOIPage;
    }

    /**
     * 修改主订单数量总价等
     *
     * @param req
     * @return
     */
    public OrderDTO updateOrderHeader(OrderHeaderUpdateReq req) {
        OrderHeader orderHeader = orderHeaderService.lambdaQuery().eq(OrderHeader::getOrderHeaderId, req.getOrderHeaderId()).eq(OrderHeader::getDeletedVersion, 0).one();
        if (Objects.isNull(orderHeader)) {
            return new OrderDTO();
        }
        if (Objects.nonNull(req.getAmount())) {
            orderHeader.setAmount(req.getAmount());
        }
        if (Objects.nonNull(req.getTotalQuantity())) {
            orderHeader.setTotalQuantity(req.getTotalQuantity());
        }
        orderHeader.setUpdatedBy(SecurityUtils.getUserId());
        orderHeader.setUpdatedTime(new Date());
        orderHeaderService.updateById(orderHeader);
        return OrderHeaderMapping.INSTANCE.coverToResp(orderHeader);
    }

    /**
     * 修改子订单单价 数量 总价
     *
     * @param req
     * @return
     */
    public OrderItemDTO updateOrderItem(OrderItemPriceReq req) {
        OrderItem orderItem = orderItemService.lambdaQuery().eq(OrderItem::getOrderItemId, req.getOrderItemId()).eq(OrderItem::getDeletedVersion, 0).one();
        if (Objects.isNull(orderItem)) {
            return new OrderItemDTO();
        }
        if (Objects.nonNull(req.getTotalPrice())) {
            orderItem.setTotalPrice(req.getTotalPrice());
        }
        if (Objects.nonNull(req.getQuantity())) {
            orderItem.setQuantity(req.getQuantity());
        }
        if (Objects.nonNull(req.getUnitPrice())) {
            orderItem.setUnitPrice(req.getUnitPrice());
        }
        orderItem.setUpdatedBy(SecurityUtils.getUserId());
        orderItem.setUpdatedTime(new Date());
        orderItemService.updateById(orderItem);
        return OrderItemMapping.INSTANCE.coverToResp(orderItem);
    }

    private void fillOtherProperties(OrderDTO orderDTO, List<OrderItemDTO> itemDTOS) {
        // 处理品牌名称、商品名称和口味数量
        if (CollUtil.isEmpty(itemDTOS)) {
            return;
        }
        Set<String> goodsSet = new TreeSet<>();
        Set<String> flavorSet = Sets.newHashSet();
        itemDTOS.forEach(itemDTO -> {
            goodsSet.add(itemDTO.getGoodsName());
            flavorSet.add(itemDTO.getTasteName());
            itemDTO.setItemStatusDesc(OrderItemStatusEnum.getOrderItemStatusByCode(itemDTO.getItemStatus()).getDescEn());
        });
        List<String> goodsNames = Lists.newArrayList();
        goodsNames.addAll(goodsSet);
        String goodsNameValue = String.join(",", goodsNames);
        orderDTO.setGoodsNames(goodsNameValue);
        orderDTO.setFlavorQuantity(flavorSet.size());
        orderDTO.setOrderItemList(itemDTOS);
    }

    public BigDecimal getGoodsPriceByQuantity(Long goodsId, Integer quantity) {
        // 查询商品信息
        Goods goods = goodsService.getOne(new LambdaQueryWrapper<Goods>()
                .eq(Goods::getGoodsId, goodsId)
                .eq(Goods::getDeletedVersion, 0));
        if (Objects.isNull(goods)) {
            throw new ServiceException("Goods does not exist.");
        }
        BigDecimal unitPrice = Objects.nonNull(goods.getCurrentWholesaleUnitPrice()) ? goods.getCurrentWholesaleUnitPrice() : goods.getWholesaleUnitPrice();
        return getGoodsPriceByQuantity(goodsId, quantity, unitPrice);
    }

    /**
     * 从缓存中加载全部阶梯价，对于给定商品，若缓存中不存在，则从重新db获取数据
     *
     * @return
     */
    private Map<Long, List<PriceTier>> loadPriceTierData() {
        String cacheKey = CacheBusinessConstants.PRICE_TIER_CACHE;
        Map<Long, List<PriceTier>> priceRanges;
        if (Boolean.TRUE.equals(redisService.hasKey(cacheKey))) {
            String cacheValue = redisService.getCacheObject(cacheKey);
            priceRanges = Objects.nonNull(cacheValue) ? JSON.parseObject(cacheValue, new TypeReference<Map<Long, List<PriceTier>>>() {
            }, JSONReader.Feature.IgnoreNoneSerializable) : null;
        } else {
            // 查询商品信息
            List<PriceTier> priceTiers;
            priceTiers = priceTierService.list(new LambdaQueryWrapper<PriceTier>().eq(PriceTier::getDeletedVersion, 0));
            priceTiers.forEach(item -> {
                if (Objects.isNull(item.getMinQuantity())) {
                    item.setMinQuantity(0);
                }
                if (Objects.isNull(item.getMaxQuantity())) {
                    item.setMaxQuantity(Integer.MAX_VALUE);
                }
            });
            priceRanges = priceTiers.stream().collect(Collectors.groupingBy(PriceTier::getGoodsId));
            redisService.setCacheObject(cacheKey, JSONObject.toJSONString(priceRanges), 1L, TimeUnit.DAYS);
        }
        return priceRanges;
    }

    /**
     * 根据商品数量调价，当商品没有阶梯价，则使用原价
     *
     * @param goodsId  商品编码
     * @param quantity 商品数量
     * @return 商品价格
     */
    public BigDecimal getGoodsPriceByQuantity(Long goodsId, Integer quantity, BigDecimal defaultUnitPrice) {
        Map<Long, List<PriceTier>> priceRanges = loadPriceTierData();
        if (CollectionUtils.isEmpty(priceRanges) || !priceRanges.containsKey(goodsId)) {
            return defaultUnitPrice;
        } else {
            // 如果数量不在阶梯价范围内，则抛出异常
            boolean quantityValid = false;
            for (PriceTier priceTier : priceRanges.get(goodsId)) {
                if (priceTier.getMinQuantity().compareTo(quantity) <= 0 && priceTier.getMaxQuantity().compareTo(quantity) >= 0) {
                    quantityValid = true;
                }
            }
            if (!quantityValid) {
                throw new ServiceException("quantity is not in price ranges.");
            }
            return QLExpressUtils.calculatePriceByPriceTier(goodsId, priceRanges, quantity, goodsConfig.getPriceTierExpression());
        }
    }

    /**
     * 更新主订单的状态。如果订单已完成，则忽略
     *
     * @param orderHeaderId 主订单id
     * @param status        订单状态
     */
    public void updateOrderStatus(Long orderHeaderId, OrderHeaderStatusEnum status) {
        OrderHeader orderHeader = orderHeaderService.getById(orderHeaderId);
        if (orderHeader == null) {
            log.warn("order does not exist, ignore update status.");
            return;
        }
        Integer headerStatus = orderHeader.getHeaderStatus();
        if (OrderHeaderStatusEnum.ORDER_COMPLETED.getCode().equals(headerStatus)) {
            log.warn("order has been completed, ignore update status.");
            return;
        }
        orderHeaderService.lambdaUpdate()
                .set(OrderHeader::getHeaderStatus, status.getCode())
                .eq(OrderHeader::getOrderHeaderId, orderHeaderId)
                .eq(OrderHeader::getDeletedVersion, 0)
                .update();
    }

    /**
     * 更新主订单的状态
     *
     * @param orderHeaderId 主订单id
     * @param status        订单状态
     */
    public void refreshOrderStatus(Long orderHeaderId, Integer status) {
        orderHeaderService.update(new LambdaUpdateWrapper<OrderHeader>().
                set(OrderHeader::getHeaderStatus, status).eq(OrderHeader::getOrderHeaderId, orderHeaderId).
                eq(OrderHeader::getDeletedVersion, 0)
        );
    }

    public boolean updateEstimateArrivalTime(Long orderHeaderId, Date arrivalTime) {
        return orderHeaderService.lambdaUpdate()
                .set(OrderHeader::getEstimateArrivalTime, arrivalTime)
                .eq(OrderHeader::getOrderHeaderId, orderHeaderId)
                .update();
    }

    /**
     * 获取主订单的订单状态枚举
     */
    public List<SysDictDataDTO> getOrderHeaderStatusEnum() {
        OrderHeaderStatusEnum[] values = OrderHeaderStatusEnum.values();
        List<SysDictDataDTO> dictList = new ArrayList<>(values.length);
        for (OrderHeaderStatusEnum statusEnum : values) {
            if (statusEnum == OrderHeaderStatusEnum.ORDER_COMPLETED) {
                continue;
            }
            SysDictDataDTO dictDataDTO = new SysDictDataDTO();
            dictDataDTO.setDictLabel(statusEnum.getDescCn());
            dictDataDTO.setDictDesc(statusEnum.getDesc());
            dictDataDTO.setDictValue(statusEnum.getCode().toString());
            dictList.add(dictDataDTO);
        }
        return dictList;
    }


    /**
     * 保存定制单
     *
     * @param reqs 定制单请求模型
     * @return 定制单id
     */
    public void saveOrderCustomized(List<OrderCustomizedReq> reqs) {
        List<OrderCustomized> customizeds = OrderCustomizedMapping.INSTANCE.coverListToEntity(reqs);
        orderCustomizedService.saveOrUpdateBatch(customizeds);
        Map<String, OrderCustomized> customizedMap = customizeds.stream().collect(Collectors.toMap(OrderCustomized::getTasteName, item -> item));
        reqs.forEach(item -> item.setOrderCustomizedId(customizedMap.get(item.getTasteName()).getOrderCustomizedId()));
        List<Long> objIds = reqs.stream().map(OrderCustomizedReq::getOrderCustomizedId).collect(Collectors.toList());
        attachmentService.lambdaUpdate().setSql(" deleted_version=attachment_id ").in(Attachment::getObjectId, objIds).eq(Attachment::getDeletedVersion, 0);
        List<Attachment> attachments = Lists.newArrayList();
        reqs.forEach(item -> {
            if (Objects.nonNull(item.getCustomPackages()) && StringUtils.isNotEmpty(item.getCustomPackages().getUrl())) {
                Attachment attachment = AttachmentMapping.INSTANCE.coverToEntityResp(item.getCustomPackages());
                attachment.setObjectId(item.getOrderCustomizedId());
                attachments.add(attachment);
            }
        });
        attachmentService.saveBatch(attachments);
    }

    /**
     * 查询定制单详情
     *
     * @param orderHeaderId 定制单id
     * @return 定制单详情实体
     */
    public List<OrderCustomizedDTO> getOrderCustomizedById(Long orderHeaderId) {
        List<OrderItem> orderItems = orderItemService.listByOrderHeaderId(orderHeaderId);
        List<Long> customizedIds = orderItems.stream().map(OrderItem::getOrderCustomizedId).collect(Collectors.toList());
        List<OrderCustomized> orderCustomizeds = orderCustomizedService.listByIds(customizedIds);
        List<OrderCustomizedDTO> orderCustomizedDTOS = OrderCustomizedMapping.INSTANCE.coverListToResp(orderCustomizeds);
        List<Long> objIds = orderCustomizedDTOS.stream().map(OrderCustomizedDTO::getOrderCustomizedId).collect(Collectors.toList());
        List<Attachment> attachments = attachmentService.lambdaQuery().in(Attachment::getObjectId, objIds).eq(Attachment::getDeletedVersion, 0).list();
        List<AttachmentResp> attachmentRespList = AttachmentMapping.INSTANCE.coverListToResp(attachments);
        Map<Long, AttachmentResp> attachmentMap = attachmentRespList.stream().collect(Collectors.toMap(AttachmentResp::getObjectId, item -> item));
        orderCustomizedDTOS.forEach(item -> item.setCustomPackages(attachmentMap.get(item.getOrderCustomizedId())));
        return orderCustomizedDTOS;
    }

    /**
     * 确认定制单
     *
     * @param orderHeaderId 订单id
     */
    public void confirmOrderCustomized(Long orderHeaderId) {
        OrderHeader orderHeader = orderHeaderService.getOne(new LambdaQueryWrapper<OrderHeader>()
                .eq(OrderHeader::getOrderHeaderId, orderHeaderId)
                .eq(OrderHeader::getDeletedVersion, 0)
        );
        if (Objects.isNull(orderHeader)) {
            return;
        }
        orderHeader.setHeaderStatus(OrderHeaderStatusEnum.WAITING_CONFIRMATION.getCode());
        orderHeaderService.saveOrUpdate(orderHeader);
        syncConfirmOrRejectToIntranet(orderHeaderId, true, null);
    }

    /**
     * 拒绝定制订单
     */
    public void rejectOrderItemCustomized(OrderSaveReq req) {
        int customOrderNum = orderItemService.count(new LambdaQueryWrapper<OrderItem>()
                .eq(OrderItem::getOrderHeaderId, req.getOrderHeaderId())
                .eq(OrderItem::getDeletedVersion, 0)
                .isNotNull(OrderItem::getOrderCustomizedId)
        );
        OrderHeader orderHeader = orderHeaderService.getOne(new LambdaQueryWrapper<OrderHeader>()
                .eq(OrderHeader::getOrderHeaderId, req.getOrderHeaderId())
                .eq(OrderHeader::getHeaderStatus, OrderHeaderStatusEnum.WAITING_CONFIRMATION.getCode())
        );
        if (Objects.isNull(orderHeader) || customOrderNum <= 0) {
            throw new ServiceException("Custom order item not found.");
        }
        orderHeader.setHeaderStatus(OrderHeaderStatusEnum.REJECTED.getCode());
        orderHeader.setRemark(req.getRemark());
        orderHeaderService.saveOrUpdate(orderHeader);
        syncConfirmOrRejectToIntranet(req.getOrderHeaderId(), false, req.getRemark());
    }

    private String buildShoppingCartKey(Long userId) {
        return MessageFormat.format(CacheBusinessConstants.CHANNEL_SHOPPING_CART_CACHE, userId.toString());
    }

    private String buildShoppingCartKey() {
        return buildShoppingCartKey(SecurityUtils.getUserId());
    }

    /**
     * 计算折后价，这个价不入缓存，仅临时计算在前端展示，会员折扣比例会入缓存，用于后续的订单金额计算
     *
     * @param cartDTO 购物车
     */
    private void calcDiscountedMemberPrice(ShoppingCartDTO cartDTO) {
        if (Objects.nonNull(cartDTO) && Objects.nonNull(cartDTO.getDiscountAmount()) && Objects.nonNull(cartDTO.getMembershipDiscount())) {
            BigDecimal membershipAmount = cartDTO.getDiscountAmount().multiply(cartDTO.getMembershipDiscount());
            BigDecimal discount = cartDTO.getDiscountAmount().subtract(membershipAmount).add(cartDTO.getDiscount());
            cartDTO.setDiscountAmount(membershipAmount);
            cartDTO.setDiscount(discount);
        }
    }

    /**
     * 获取阶梯价后的会员折扣比例,没有会员激励时会员折扣比例为1
     * 1. 激活的会员折扣: 先查询该用户是否有指定的会员激励， 没有则使用全局的会员激励，若没有全局的会员激励则不打折
     * todo 用户会员激励可以使用缓存
     *
     * @param amount 订单的总金额
     * @return
     */
    private BigDecimal getMembershipDiscount(BigDecimal amount) {
        // 初始化会员折扣为1，即没有折扣
        BigDecimal membershipDiscount = BigDecimal.ONE;
        // 如果订单总金额为0，则直接返回，不给予折扣
        if (amount.equals(BigDecimal.ZERO)) {
            return membershipDiscount;
        }
        // 尝试根据当前用户获取特定的会员政策
        MembershipPolicyDTO membershipPolicy = membershipPolicyService.selectMembershipPolicyByUser(SecurityUtils.getUserId());
        // 如果没有特定的会员政策，则尝试获取全局的会员政策
        if (Objects.isNull(membershipPolicy)) {
            MembershipPolicy globalMembershipPolicy = membershipPolicyService.lambdaQuery()
                    .eq(MembershipPolicy::getDeletedVersion, 0)
                    .eq(MembershipPolicy::getHasSpecificUser, false)
                    .eq(MembershipPolicy::getStatus, 1)
                    .one();
            if (Objects.nonNull(globalMembershipPolicy)) {
                membershipPolicy = MembershipMapping.INSTANCE.coverToResp(globalMembershipPolicy);
            }
        }
        // 如果存在有效的会员政策，并且有最小金额限制
        if (Objects.nonNull(membershipPolicy) && Objects.nonNull(membershipPolicy.getMinAmount())) {
            // 计算最小和最大折扣金额范围
            BigDecimal minAmount = membershipPolicy.getMinAmount().multiply(new BigDecimal(GoodsConstant.MEMBERSHIP_UNIT));
            BigDecimal maxAmount = new BigDecimal(Integer.MAX_VALUE);
            if (Objects.nonNull(membershipPolicy.getMaxAmount())) {
                maxAmount = membershipPolicy.getMaxAmount().multiply(new BigDecimal(GoodsConstant.MEMBERSHIP_UNIT));
            }
            // 如果订单金额在会员政策的折扣范围内，则计算折扣比例
            if (amount.compareTo(minAmount) >= 0 && amount.compareTo(maxAmount) <= 0) {
                membershipDiscount = BigDecimal.ONE.subtract(membershipPolicy.getDiscount().divide(ONE_HUNDRED, RoundingMode.HALF_UP)).setScale(2, RoundingMode.HALF_UP);
            }
        }
        // 返回最终计算的会员折扣比例
        return membershipDiscount;
    }

    /**
     * 更新订单相关任务处理状态
     *
     * @param orderHeaderId 订单头
     * @param processStatus 订单处理状态
     * @param processItem   处理项
     * @return
     */
    public Boolean updateOrderProcessStatus(Long orderHeaderId, Integer processStatus, Integer processItem) {
        log.info("Update order process status. orderHeaderId: {}, processStatus: {}, processItem: {}", orderHeaderId, processStatus, processItem);
        OrderProcessTypeEnum processTypeEnum = OrderProcessTypeEnum.getOrderProcessTypeByCode(processItem);
        if (processTypeEnum == null) {
            throw new ServiceException("Invalid order process type.");
        }
        OrderHeader orderHeader = orderHeaderService.getById(orderHeaderId);
        if (orderHeader == null) {
            throw new ServiceException("Order not found.");
        }
        if (processStatus != null) {
            processStatus = OrderConstant.ORDER_PROCESS_STATUS_UNDO.equals(processStatus) ? OrderConstant.ORDER_PROCESS_STATUS_UNDO : OrderConstant.ORDER_PROCESS_STATUS_DONE;
        }
        return orderHeaderService.lambdaUpdate()
                .eq(OrderHeader::getOrderHeaderId, orderHeaderId)
                .set(OrderProcessTypeEnum.CONTRACT == processTypeEnum, OrderHeader::getContractStatus, processStatus)
                .set(OrderProcessTypeEnum.DOWN_PAYMENT == processTypeEnum, OrderHeader::getDownPaymentStatus, processStatus)
                .set(OrderProcessTypeEnum.FINAL_PAYMENT == processTypeEnum, OrderHeader::getFinalPaymentStatus, processStatus)
                .update();
    }

    /**
     * 获取合同签署访问链接
     *
     * @param orderHeaderId 订单头ID
     * @return
     */
    public R<String> getCustomerContractUrl(Long orderHeaderId) {
        return outerNetWorkbenchService.getCustomerContractUrl(orderHeaderId);
    }

    public R<OrderPayInfoResp> getPayInfo(Long orderHeaderId, Integer payType) {
        return outerNetWorkbenchService.getPayInfo(orderHeaderId, payType);
    }

    public R<Boolean> uploadPaymentVoucher(UploadPaymentVoucherReq req) {
        return outerNetWorkbenchService.uploadPaymentVoucher(req);
    }

    public List<FileInfo> getShipmentFile(Long orderHeaderId) {
        R<List<FileInfo>> shipmentFile = outerNetWorkbenchService.getShipmentFile(orderHeaderId);
        if (R.isSuccess(shipmentFile)) {
            List<FileInfo> data = shipmentFile.getData();
            if (CollectionUtils.isEmpty(data)) {
                return new ArrayList<>();
            }
            data.forEach(item -> item.setUrl(FileUrlUtils.getHiSMKDigFileUrl(item.getUrl())));
            return data;
        }
        log.error("Get shipment file failed. orderHeaderId: {}, {}", orderHeaderId, shipmentFile.getMsg());
        return new ArrayList<>();
    }

    /**
     * 上传文件到内网obs
     *
     * @param file
     * @return
     */
    public R<String> uploadAttachment(MultipartFile file) throws IOException {
        return outerNetWorkbenchService.upload(file);
    }

    @Transactional
    public Boolean syncOrderInfo(OrderDataSyncReq orderHeaderReq) {
        log.info("Sync order info. orderHeaderReq: {}", orderHeaderReq);
        Long orderHeaderId = orderHeaderReq.getOrderHeaderId();
        OrderHeader orderHeader = orderHeaderService.getById(orderHeaderId);
        if (orderHeader == null) {
            throw new ServiceException("Order not found.");
        }
        // 更新订单头信息
        orderHeaderService.lambdaUpdate()
                .set(OrderHeader::getTotalQuantity, orderHeaderReq.getTotalQuantity())
                .set(OrderHeader::getAmount, orderHeaderReq.getAmount())
                .eq(OrderHeader::getOrderHeaderId, orderHeaderId)
                .update();
        // 更新订单明细
        List<OrderItem> dbItems = orderItemService.lambdaQuery()
                .eq(OrderItem::getOrderHeaderId, orderHeaderId)
                .eq(OrderItem::getDeletedVersion, 0)
                .list();

        List<OrderDataSyncDetail> orderItemList = orderHeaderReq.getOrderItemList();
        List<OrderItem> orderItems = OrderItemMapping.INSTANCE.convertToEntity(orderItemList);

        DataCompareHelper.CompareResult<OrderItem> compareResult = DataCompareHelper.<OrderItem>builder()
                .oldDataSupplier(() -> dbItems)
                .newDataSupplier(() -> orderItems)
                .uniqueKeyFunction(OrderItem::getOrderItemId)
                .updatePredicate((newItem, oldItem) -> !newItem.equals(oldItem))
                .genDelete(true)
                .build()
                .compare();
        List<OrderItem> toAdd = compareResult.getToAdd();
        List<OrderItem> toUpdate = compareResult.getToUpdate();
        List<OrderItem> toDelete = compareResult.getToDelete();
        if (CollectionUtils.isNotEmpty(toAdd)) {
            orderItemService.saveBatch(toAdd);
        }
        if (CollectionUtils.isNotEmpty(toUpdate)) {
            orderItemService.updateBatchById(toUpdate);
        }
        if (CollectionUtils.isNotEmpty(toDelete)) {
            orderItemService.lambdaUpdate()
                    .in(OrderItem::getOrderItemId, toDelete.stream().map(OrderItem::getOrderItemId).collect(Collectors.toList()))
                    .setSql("deleted_version = order_item_id ")
                    .update();
        }
        return true;
    }
}
